package com.lagou.edu.context;

import com.lagou.edu.context.fatory.BeanFacotory;
import com.lagou.edu.context.fatory.CachingMetadataReaderFactory;
import com.lagou.edu.context.fatory.MetadataReaderFactory;
import com.lagou.edu.context.stereotype.AutoWired;
import com.lagou.edu.context.stereotype.Component;
import com.lagou.edu.context.util.BeanInstanceUtils;

import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;

/**
 * @Author zhaozuowen
 * @Description 类路径beandefinition扫描器
 * @Date 2020-01-11 11:33
 **/

public class ClassPathBeanDefinitionScanner {

    private BeanFacotory beanFacotory;

    private MetadataReaderFactory metadataReaderFactory;

    private ClassResolver classResolver;

    private Set<TypeFilter> includeFilters=new HashSet<>();

    private BeanNameGenerater beanNameGenerater;


    public ClassPathBeanDefinitionScanner(BeanFacotory beanFacotory) {
        this.beanFacotory=beanFacotory;
        registerDefaultFilters();
    }

    private void registerDefaultFilters() {
        includeFilters.add(new AnnotationTypeFilters(Component.class.getName()));
    }

    public void scan(String... basePackages) throws InstantiationException, IllegalAccessException {
        System.out.println("开始扫描之前");
        doScan(basePackages);
    }

    private void doScan(String... basePackages) throws IllegalAccessException, InstantiationException {

        for (String basePackage : basePackages) {
            //获取资源解析器来将类路径下的指定包封存成resources资源
            Set<Class<?>> classes =getClassResolver().getClasses(basePackage);
            //将class对象封存成MetadataReader对象
            for (Class<?> aClass : classes) {
                MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(aClass);
                //判断该类有自定义的注解componet
                if(isCandidateComponent(metadataReader)){
                    if(canInstance(metadataReader)){
                        Object instance =instance(metadataReader);
                        String beanName=getBeanNameGenerater().getBeanName(metadataReader);
                        beanFacotory.register(beanName,instance);
                    }


                }
            }
            beanFacotory.populateProperties();



        }

    }
    private static boolean canInstance(MetadataReader metadataReader) {
        Class<?> classes = metadataReader.getClasses();
        if(classes.isAnonymousClass()||classes.isEnum()||classes.isAnnotation()||classes.isInterface()||classes.isMemberClass()){
            return false;
        }
        return true;
    }

    private BeanNameGenerater getBeanNameGenerater() {

        if(this.beanNameGenerater==null){
            this.beanNameGenerater=new SimpleBeanNameGenerater();
        }
        return beanNameGenerater;
    }

    private void poputePropeties(Object instance) throws IllegalAccessException {

        Field[] declaredFields = instance.getClass().getDeclaredFields();
        for (Field declaredField : declaredFields) {
            AutoWired annotation = declaredField.getAnnotation(AutoWired.class);
            if(annotation!=null){
                //获取注入属性的类型，然后从
                Class<?> type = declaredField.getType();
                declaredField.setAccessible(true);
                declaredField.set(instance,beanFacotory.getBean(type));
            }

        }

    }

    private Object instance(MetadataReader metadataReader) throws InstantiationException, IllegalAccessException {
        Class<?> classes = metadataReader.getClasses();
        return BeanInstanceUtils.instance(classes);
    }

    private boolean isCandidateComponent(MetadataReader metadataReader) {

        for (TypeFilter includeFilter : includeFilters) {
              if(includeFilter.ifMatch(metadataReader)){
                  return true;
            }

        }
        return false;
    }

    private ClassResolver getClassResolver() {
        if(this.classResolver==null){
            classResolver=new ClassPathResolver();
        }
        return classResolver;
    }


    public final MetadataReaderFactory getMetadataReaderFactory() {
        if (this.metadataReaderFactory == null) {
            this.metadataReaderFactory = new CachingMetadataReaderFactory();
        }
        return this.metadataReaderFactory;
    }

}
